"""
版本说明：优化版，减少冗余代码，提高可维护性
"""
import time
import os
import sqlite3
from threading import Thread, Lock as threading_Lock
import numpy as np
import pandas as pd
from tqsdk import TqApi, TqAuth, TqKq
from rich.console import Console
from rich.theme import Theme
from MyTT import REF, EMA, SUM
import logging

# 配置日志记录
logging.basicConfig(
    filename='trading_log.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# 改变控制台背景色和字体色，控制台窗口大小
os.system("COLOR 02")
os.system("mode con cols=150 lines=50")

# 定义颜色主题
custom_theme = Theme({
    "info": "bright_cyan",
    "warning": "bright_yellow",
    "error": "bright_red",
    "success": "bright_green",
    "trade": "bold bright_magenta"
})
console = Console(theme=custom_theme)

# 定义全局变量
symbols = []
api = None
threads = []
opened_positions = set()  # 记录已开仓的品种
position_lock = threading_Lock()  # 添加锁以保护 opened_positions 的并发访问

# 常量定义
ORDER_TIMEOUT = 0.3  # 订单超时时间（秒）
DEFAULT_STOP_LOSS_LIMIT = 3000  # 默认止损限额
DEFAULT_MTP = 5  # 默认移动止盈止损周期

# 工具函数：数据库连接装饰器
def with_db_connection(func):
    def wrapper(*args, **kwargs):
        conn = sqlite3.connect('trade_monitor.db')
        cursor = conn.cursor()
        try:
            result = func(cursor, *args, **kwargs)
            conn.commit()
            return result
        except Exception as e:
            conn.rollback()
            raise e
        finally:
            conn.close()
    return wrapper

# 工具函数：格式化时间
def get_formatted_time():
    return time.strftime('%Y-%m-%d %H:%M:%S')

# 工具函数：日志记录
def log_trade(level, message, style=None):
    logging.log(level, message)
    if style:
        console.print(message, style=style)
    else:
        console.print(message)

# 工具函数：检查订单是否活跃
def is_order_active(order):
    return order.get('status') not in ('FINISHED', 'CANCELED')

# 工具函数：等待订单成交
def wait_for_order_fill(api, order_id, timeout=ORDER_TIMEOUT):
    deadline = time.time() + timeout
    while time.time() < deadline:
        api.wait_update(deadline=deadline)
        order = api.get_order(order_id)
        if order and order['status'] == 'FINISHED':
            return True
    return False

# 工具函数：平仓操作
def close_position(api, symbol, direction, offset, volume, price, reason):
    order_id = api.insert_order(
        symbol=symbol,
        direction=direction,
        offset=offset,
        volume=volume,
        limit_price=price
    )
    log_trade(logging.INFO, f"平仓操作: {symbol} {direction} {volume}手 @ {price}, 原因: {reason}", "trade")
    return order_id

# 检查是否有未完成订单和实际持仓
def check_position_and_orders(api, symbol):
    try:
        # 检查持仓情况
        position = api.get_position(symbol)
        if position.pos_long > 0:
            return False, f"{symbol}已有{position.pos_long}手多仓持仓"
        if position.pos_short > 0:
            return False, f"{symbol}已有{position.pos_short}手空仓持仓"
        
        # 检查未完成订单
        orders = api.get_order()
        order_list = orders.list() if hasattr(orders, 'list') and callable(orders.list) else list(orders)
        
        for order in order_list:
            if is_order_active(order):
                return False, f"{symbol}有未完成订单"
        
        return True, "可以开仓"
    except Exception as e:
        log_trade(logging.ERROR, f"检查{symbol}持仓和订单时出错: {str(e)}", "error")
        return False, f"检查出错: {str(e)}"

# 获取 config 表所有配置项
@with_db_connection
def get_all_configs(cursor):
    cursor.execute("SELECT key, value FROM config")
    return dict(cursor.fetchall())

# 获取监控品种列表
@with_db_connection
def get_symbols(cursor):
    cursor.execute("SELECT exchange_code FROM products WHERE is_monitored=1")
    return [product[0] for product in cursor.fetchall()]

# 记录交易到数据库
def insert_trade_record(trade_time, symbol, direction, action_type, volume, price, remark):
    try:
        if not trade_time:
            trade_time = get_formatted_time()
        
        price = float(price) if price else 0.0
        
        @with_db_connection
        def _insert_record(cursor):
            cursor.execute(
                "INSERT INTO trade_records (trade_time, symbol, direction, action_type, volume, price, remark) "
                "VALUES (?, ?, ?, ?, ?, ?, ?)",
                (trade_time, symbol, direction, action_type, volume, price, remark)
            )
        
        _insert_record()
        log_trade(logging.INFO, f"交易记录已成功插入数据库: {symbol} {direction} {volume}手 @ {price}", "success")
    except Exception as e:
        log_trade(logging.ERROR, f"记录交易到数据库时出错: {e}", "error")

# 止损逻辑
def stop_loss(symbol):
    try:
        @with_db_connection
        def _get_stop_loss_params(cursor):
            cursor.execute("SELECT limit_stoploss, mtp, dks FROM products WHERE exchange_code=? AND is_monitored=1", (symbol,))
            result = cursor.fetchone()
            if result is None:
                return DEFAULT_STOP_LOSS_LIMIT, DEFAULT_MTP, "双向"
            stop_loss_limit = int(result[0])
            mtp = max(1, min(int(result[1]), 3600)) if result[1] else DEFAULT_MTP
            dks = str(result[2])
            return stop_loss_limit, mtp, dks
        
        stop_loss_limit, mtp, dks = _get_stop_loss_params()
        log_trade(logging.WARNING, f"{get_formatted_time()} 开始检查{symbol}止损条件", "warning")
        
        klines = api.get_kline_serial(symbol, 60 * mtp, data_length=300)
        quote = api.get_quote(symbol)
        position = api.get_position(symbol)
        orders = api.get_order(symbol)

        # 撤销所有未成交订单
        for order in orders.items():
            if is_order_active(order):
                api.cancel_order(order)

        # 限额止损检查
        if position.pos_short > 0:
            short_loss_per_hand = (position.open_price_short - quote.last_price) * quote.volume_multiple
            if short_loss_per_hand > stop_loss_limit:
                offset = "CLOSETODAY" if symbol.startswith('SHFE') and position.pos_short_today > 0 else "CLOSE"
                volume = position.pos_short_today if symbol.startswith('SHFE') and position.pos_short_today > 0 else position.pos_short
                if volume > 0:
                    price = quote.ask_price1 + 2 * quote.price_tick
                    order_id = close_position(api, symbol, "BUY", offset, volume, price, "限额止损")
                    if wait_for_order_fill(api, order_id):
                        insert_trade_record(get_formatted_time(), symbol, "BUY", offset, volume, price, "限额止损")
                    else:
                        api.cancel_order(order_id)
                        log_trade(logging.WARNING, f"{symbol}空仓平仓订单未成交，已撤销", "warning")

        if position.pos_long > 0:
            long_loss_per_hand = (quote.last_price - position.open_price_long) * quote.volume_multiple
            if long_loss_per_hand > stop_loss_limit:
                offset = "CLOSETODAY" if symbol.startswith('SHFE') and position.pos_long_today > 0 else "CLOSE"
                volume = position.pos_long_today if symbol.startswith('SHFE') and position.pos_long_today > 0 else position.pos_long
                if volume > 0:
                    price = quote.bid_price1 - 2 * quote.price_tick
                    order_id = close_position(api, symbol, "SELL", offset, volume, price, "限额止损")
                    if wait_for_order_fill(api, order_id):
                        insert_trade_record(get_formatted_time(), symbol, "SELL", offset, volume, price, "限额止损")
                    else:
                        api.cancel_order(order_id)
                        log_trade(logging.WARNING, f"{symbol}多仓平仓订单未成交，已撤销", "warning")

    except Exception as e:
        log_trade(logging.ERROR, f"止损逻辑执行出错: {e}", "error")
